#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
@FileName: ioi_ed2.py
@Version: 1.0
@Date: 2023/6/21 15:41
@Description: 逆二次插值, 使用最新估计 x3 代替 后向误差最大的 xi
"""

import math
from root_paras import Paras


def ioi(fun, paras: Paras = Paras()) -> tuple[float, float, float]:
    x0: float = paras.start
    x1: float = paras.end

    sec_tol = paras.sec_tol
    if math.fabs(x1 - x0) < 2.0 * sec_tol:
        x1 = x0 + paras.dft_sect
    x2: float = (x0 + x1) / 2.0

    n: int = 0
    sol_tol = paras.sol_tol
    loops = paras.loops
    while math.fabs(x2 - x1) > sec_tol:
        n += 1
        if n > loops:
            raise RuntimeError(f'ioi2 iteration: loop over 1000 times, with interval {x2 - x1}')

        # 参数重新排序
        y0, y1, y2 = math.fabs(fun(x0)), math.fabs(fun(x1)), math.fabs(fun(x2))
        if y1 < y0 and y2 < y0:
            x2, x0 = x0, x2
        elif y0 < y1 and y2 < y1:
            x2, x1 = x1, x2

        if math.fabs(val := fun(x0)) < sol_tol:
            print(f'IOI method, f(x0) = {val} ~> 0')
        if math.fabs(val := fun(x1)) < sol_tol:
            print(f'IOI method, f(x1) = {val} ~> 0')

        q = fun(x0) / fun(x1)
        r = fun(x2) / fun(x1)
        s = fun(x2) / fun(x0)
        numer = r * (r - q) * (x2 - x1) + (1.0 - r) * s * (x2 - x0)
        denom = (q - 1) * (r - 1) * (s - 1)
        term2 = -numer / denom
        x0, x1, x2 = x1, x2, x2 + term2

        if math.fabs(fun(x2) - 0) <= sol_tol:
            break

    if math.fabs((val := fun(x2)) - 0) <= sol_tol:
        print(n)
        return x2, x0, x1
    else:
        raise RuntimeError(f'Secant iteration: did not converge to zero, instead -> {val}')


if __name__ == '__main__':
    fun = lambda x: x ** 3 + x - 1
    res = ioi(fun)
    print(res)
